package data;

import java.lang.reflect.Field;

import java.sql.*;

import java.util.ArrayList;

import java.util.List;



public class DataConnection<T> {

    //连接数据库的驱动程序的字符常量

    private static final String DBDRIVER="org.gjt.mm.mysql.Driver";

    //连接数据库地址,其中jdbc是连接数据库的主协议;mysql是子协议;localhost:3306是我们在本机上安装的mysql数据库管理服务器名，shopdata是在mysql数据库系统中创建的数据库名

    private static final String DBURL="jdbc:mysql://localhost:3306/shopdata";

    //连接数据库管理员，是mysql数据库的系统管理员root

    private static final String DBUSER="root";

    //连接数据库管理员登录密码,是在安装mysql数据库时，给定的密码,你要根据你实际需要来写

    private static final String DBPASS="0118";

    private static Connection conn=null;



    /**

     * 方法用于获取数据库连接对象

     * @return 连接成功返回数据库连接对象（Connection类的对象）

     */

    public static Connection getConn(){

        try {

            //加载驱动程序

            Class.forName(DBDRIVER);

            //获取数据库连接对象

            conn=DriverManager.getConnection(DBURL, DBUSER, DBPASS);

            //连接成功返回连接对象

            return conn;

        } catch (ClassNotFoundException | SQLException e) {

            e.printStackTrace();

            //如果连接失败返回null

            return conn;

        }

    }



    /**

     * 用于对数据库操作对象进行关闭操作,一般对数据库进行操作对象都是这三个类（ResultSet,PreparedStatement ,Connection ）的对象

     * @param rs 保存从数据表取加的数据集

     * @param psta 执行sql命令的对象

     * @param conn 连接数据对象

     */

    public static void close(ResultSet rs,PreparedStatement psta,Connection conn){

        try {

            //判断rs不为空，则它存在，就关闭它

            if(rs != null){

                rs.close();

            }

            //判断psta不为空，则它存在，就关闭它

            if(psta != null){

                psta.close();

            }

            //判断conn不为空，则它存在，就关闭它

            if(conn != null){

                conn.close();

            }

        } catch (SQLException e) {

            e.printStackTrace();

        }

    }



    /**

     * 执行insert、update和delete命令的方法

     * @param sqlcomm sql命令字符串

     * @param para sql命令中参数参数所对应的值

     * @return 执行命令成功返回true，否则返回false

     */

    public static boolean request(String sqlcomm,Object ... para){

        boolean flag=false;

        try {

            //创建数据库连接

            Connection conn=getConn();

            //创建执行sql命令的对象

            PreparedStatement psta = conn.prepareStatement(sqlcomm);

            //判断命令中是否有参数，若没有参数，则把参数值的数组设置为0

            if(para==null){

                para=new Object[0];

            }



            //遍历参数列表，并进行赋值

            for(int i=0;i<para.length;i++){

                psta.setObject(i+1, para[i]);

            }



            //执行sql命令

            int i=psta.executeUpdate();

            if(i>0){

                flag= true;

            }

            close(null, psta, conn);

            return flag;

        } catch (SQLException e) {

            return false;

        }

    }



    /**

     * 用于执行查询命令

     * @param cls 数据表所对应的实体类

     * @param sql 要执行的sql查询命令

     * @param para 要执行的sql命令中参数所对应的值，若没有则为null

     * @return 返回数据集，数据集中的第一个元素都是cls的对象

     */

    public List<T> query(Class<T> cls , String sql, Object ... para){

        List<T> list = new ArrayList<>();

        try {

            conn = getConn();

            PreparedStatement psta = conn.prepareStatement(sql);

            //判断命令中是否有参数，若没有参数，则把参数值的数组设置为0

            if(para==null){

                para=new Object[0];

            }

            //遍历参数列表，并进行赋值

            for(int i=0;i<para.length;i++){

                psta.setObject(i+1, para[i]);

            }

            ResultSet rs = psta.executeQuery();

            ResultSetMetaData rsmd = rs.getMetaData();//rs中列的名称和类型的信息,并把它赋给rsmd,如：select id,name,pass from login，rsmd为得列名称为id,name,pass,列的类型为long、String、String等信息

            while(rs.next()){

                T obj = cls.newInstance(); //创建这个类的新的实例

                int col = rsmd.getColumnCount();//获取rs中的列数据，取sql命令中所给的字段 数，如 select id,name,pass from login,则col=3

                //遍历rs中所有列

                for (int i=1; i<=col; i++){

                    String DBField = rsmd.getColumnLabel(i); //获取第i列名称

                    Field field = cls.getDeclaredField(DBField); //获取cls类中定的成员变量名与列名DBField

                    field.setAccessible(true); //私有可见

                    field.set(obj, rs.getObject(i));//把rs元素中的第i个列的值，赋给对象obj的field成员变量

                }

                list.add(obj);//obj添加到list中

            }

            close(rs, psta, conn);

        } catch (Exception e) {

            e.printStackTrace();

        }

        return list;

    }

}